2021년 2학기

실습 8

웹 매핑 및 최신 동향



실습조교: 석사과정 서용훈()

Date Generated: August 31, 2021
- Troubleshooter
- RGIS Ref


※ 본 문서는 PC 환경에 최적화되어있습니다.

1 실습 목표

  1. Web GIS의 장단점을 이해하고 사례를 활용할 수 있다.

  2. R을 활용하여 상호작용이 가능한 지도를 제작할 수 있다.

  3. 제작한 지도를 웹 상에 배포할 수 있다.

2 환경 구축


2.1 설치 프로그램

이번 실습을 위해 설치하는 프로그램은 다음과 같다.

  • R(base)
  • RStudio
  • Rtools40

이 중 필수로 설치를 요하는 프로그램은 RRStudio이며, Rtools40는 추가적으로 더 배워보고 싶은 사람만 선택적으로 설치하기를 권장한다.

아래에 제시된 링크에서 설치 파일을 먼저 받는다.

R

설명

R은 프로그래밍 언어이며 통계 컴퓨팅 및 그래픽을 위한 무료 소프트웨어 환경이다. R 언어는 통계학자와 데이터 마이너들 사이에서 통계 소프트웨어 및 데이터 분석을 개발하기 위해 널리 사용된다. 조사, 데이터 마이닝 조사 및 학술 문헌 데이터베이스에 대한 연구는 R의 인기가 상당히 상승했음을 보여준다. R은 프로그래밍 언어의 인기척도인 TIOBE 지수에서 14위를 차지했다. (패키지를 통한 GIS기능 추가)


다운로드 링크

Download and Install R


RStudio

설명

RStudio는 통계 컴퓨팅 및 그래픽을 위한 프로그래밍 언어인 R을 위한 통합개발환경(Integrated Development Environment, IDE)이다.


다운로드 링크

Download the RStudio IDE


Rtools40

설명

R 및 R 패키지를 빌드하는 도구. Windows에서 직접 패키지를 빌드하거나 R 자체를 빌드하려면 필요하다. 컴파일이 필요한 패키지를 설치시 C/C++, FORTRAN 등 여러 언어의 컴파일러를 지원한다.

보충설명 - The why and the how of installing Rtools


다운로드 링크

Using Rtools40 on Windows



2.2 설치 방법

위에서 제시한 링크에서 받은 설치 파일을 다음 동영상을 참고하여 설치한다.

일반 사용자


심화 사용자



3 R Crash Course

지도를 제작시 필요한 기초 문법만 수록하였다.


3.1 변수 선언

변수 선언은 어떠한 프로그래밍 언어를 하든 꼭 필요한 작업이다. 변수를 선언해야 해당 변수에 자료를 담고, 이를 모아 연산을 하고 그 결과를 도출하며, 결과 또한 변수로 저장할 수 있기 때문이다.

R에서 변수를 선언하는 방법은 아주 간단하다. 사용할 변수명을 제시하고 해당 변수명에 들어갈 데이터를 <- 혹은 =을 사용하여 선언할 수 있다.


3.1.1 변수에 숫자 지정

다음은 숫자형 자료를 변수에 지정하는 과정이다.

# 참고: 주석 다는법

#(해시, 샵) 사용(주석처리할 라인(혹은 부분) 맨 앞에)

# 주석(comment)이란?: 프로그래밍에 있어 내용을 메모하는 목적으로 쓰이며,
# 주석 처리가 된 줄은 실행되지 않는다.


n <- 1 #n에 1을 선언
m = .1 #m에 0.1을 선언

str(n) # 자료형 확인
 num 1
str(m)
 num 0.1
nm <- n*m # 반환형식: 
          # > str(nm)
          #  num 0.1  <<< 자료형 자료값
          # 자세한 내용은 콘솔창에 ?str()

str(nm)
 num 0.1


3.1.2 변수에 문자 지정

c <- "꿈과 희망이 가득한 대학원"
c =  "꿈과 희망이 가득한 대학원" # 동일한 변수에 지정시 덮어쓰기

str(c)
 chr "꿈과 희망이 가득한 대학원"


3.1.3 변수에 배열 지정

{1,2,3,4,5}와 같이 벡터 혹은 집합과 같은 데이터를 담는 방법으로, 배열은 c()를 사용하여 생성한다.

an <- c(1,3,5,7) #an: array-number

ac <- c(c,"같이하실래요?","쪼-인","어스") #ac: array-character

str(an)
 num [1:4] 1 3 5 7
str(ac)
 chr [1:4] "꿈과 희망이 가득한 대학원" "같이하실래요?" "쪼-인" "어스"


3.1.4 변수에 데이터프레임 지정

데이터프레임은 스프레드 시트 형식으로 자료를 저장하는 구조로, 행과 열로 구성됨.

df <- data.frame(an,ac) #각 배열의 차원이 같아야 데이터 프레임으로 지정 가능

str(df)
'data.frame':   4 obs. of  2 variables:
 $ an: num  1 3 5 7
 $ ac: chr  "꿈과 희망이 가득한 대학원" "같이하실래요?" "쪼-인" "어스"


3.1.5 지정한 변수 값 반환

변수의 값을 확인하기 위해서는 커맨드 라인에 해당 변수명을 치거나 print() 함수를 사용하여 반환한다.

m         # 변수명
[1] 0.1
print(df) # print() 함수 사용
  an                        ac
1  1 꿈과 희망이 가득한 대학원
2  3             같이하실래요?
3  5                     쪼-인
4  7                      어스
an*m      # 연산 결과도 표출 가능
[1] 0.1 0.3 0.5 0.7


3.2 패키지

R 패키지는 크게 R 설치 시, 함께 설치된 base(내장) 패키지와 사용자의 사용 목적에 따라 외부패키지로 크게 구분될 수 있다. base 패키지는 주로 R의 기본문법이라고 이해해도 좋다. 다만, 외부패키지는 기본문법을 바탕으로 조금 더 편안하게 사용하고자 하는데 개발 목적이 있다.

패키지는 다시 설치와 사용방법에 따라서

  • Base system을 설치할 때 자동으로 설치가 되어 기본적인 통계분석과 그래프 작성, 데이터 처리 등에 즉시 사용이 가능한 Base packages (base, datasets, graphics, grid, methods, stats, utils 등)

  • Base system을 설치할 때 자동으로 설치가 되기는 하지만, 사용하려면 R로 불러오기를 해야만 사용이 가능한 Recommended packages (MASS, foreign, lattice 등)

  • 통계 등 분석 목적/필요에 따라 따로 설치를 하고 R로 불러오기를 해서 사용해야 하는 Other packages (tidyverse, sf, rgdal, tmap 등 다수)

로 세분화할 수 있다.

Table 1: 설치와 사용방법에 따른 Package 구분.
Package 구분 설치여부 사용시
Base Packages 자동 불러오기 불필요
Recommended Packages 자동 불러오기 필요
library(tidyverse)
Other Packages 개별설치
install.packages("Package")
불러오기 필요
library(tidyverse)


3.2.1 패키지 설치

#install.packages("새로운_패키지명")

install.packages("tidyverse")


# 패키지 제거

#remove.packages("tidyverse")

혹은 다음과 같이 RStudio에서 그래픽 인터페이스 환경으로도


3.2.2 패키지 불러오기

현재 R 세션에 패키지를 불러오기 위해서는 다음과 같은 명령이 필요하다. 예를 들어, 데이터 정제에 필수적인 tidyverse 패키지를 불러오려면,

#library(기설치된패키지명)

library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5     v purrr   0.3.4
v tibble  3.1.4     v dplyr   1.0.7
v tidyr   1.1.3     v stringr 1.4.0
v readr   2.0.1     v forcats 0.5.1
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

위와 같이 여러 메시지들이 나타나면서 정상적으로 로드가 된다.

설치시와 비슷하게 RStudio에서 그래픽 인터페이스 환경으로도

<사진>

참고로 다음과 같이 패키지를 내릴 수도 있다.

# 패키지 unload

#detach("package:tidyverse", unload = TRUE)


3.3 데이터프레임 manipulation


3.3.1 Data Frame이란?

데이터 프레임(Data frame)은 다양한 형태의 데이터가 2차원으로 구성된 데이터 구조이며, 행(케이스)과 열(변수)로 구성된 표이다. 엑셀에서 이름 필드, 연령 필드, 성적 필드 등으로 이루어진 표와 같다고 생각하면 이해가 빠를 것이다. 통계분석에 가장 많이 사용된다. GIS에서 속성 테이블(Attribute table) 또한 해당 형식으로 나타낼 수 있다.


3.3.2 데이터 프레임 구조 보기

아래는 tidyverse패키지에서 기본으로 제공하는 샘플 tibble로, 형태는 데이터 프레임과 유사하다.

table1
# A tibble: 6 x 4
  country      year  cases population
  <chr>       <int>  <int>      <int>
1 Afghanistan  1999    745   19987071
2 Afghanistan  2000   2666   20595360
3 Brazil       1999  37737  172006362
4 Brazil       2000  80488  174504898
5 China        1999 212258 1272915272
6 China        2000 213766 1280428583
str(table1)
tibble [6 x 4] (S3: tbl_df/tbl/data.frame)
 $ country   : chr [1:6] "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
 $ year      : int [1:6] 1999 2000 1999 2000 1999 2000
 $ cases     : int [1:6] 745 2666 37737 80488 212258 213766
 $ population: int [1:6] 19987071 20595360 172006362 174504898 1272915272 1280428583

데이터 프레임 또한 위와 같은 구조를 지닌다.


3.3.3 데이터 프레임 만들기

데이터 프레임을 생성하는 방법은 많다. 그 중에서 가장 많이 쓰이는 방법은 외부에서 데이터를 R에서 읽어 들이는 방법이다. 이 방법은 R 입출력에서 자세히 다루도록 하겠다.

두 번째 방법은 벡터 형식의 자료를 묶어서 데이터 프레임을 만드는 것이다. 아래 예제는 data.frame() 함수를 이용하여 벡터 변수 name, age, sex, score를 하나로 묶어서 데이터 프레임 df를 만들어 보겠다.

name <- c("유재석", "홍진영", "송가인", "강호동", "이영자", "김종민", "김연아")
age <- c(24, 28, 31, 25, 27, 22, 29)
sex <- c("남", "여", "여", "남", "여", "남", "여")
score <- c(90, 80, 85, 75, 95, 80, 70)


# 'stringsAsFactors = F' 옵션 : 문자 데이터를 factor로 변환시키지 않음
df <- data.frame(name, age, sex, score, stringsAsFactors = F)
df
    name age sex score
1 유재석  24  남    90
2 홍진영  28  여    80
3 송가인  31  여    85
4 강호동  25  남    75
5 이영자  27  여    95
6 김종민  22  남    80
7 김연아  29  여    70

세번째 방법은 수식 등의 규칙을 사용한 방법이다.

x <-  1:10    #1부터 10까지의 배열
y <-  2       #상수 2로 채워진 배열이며 길이는 x와 동일
z <- (x**2)+y #x^2 + 2 x와 y의 식으로 채워짐



num.df <- data.frame(x,y,z)

num.df
    x y   z
1   1 2   3
2   2 2   6
3   3 2  11
4   4 2  18
5   5 2  27
6   6 2  38
7   7 2  51
8   8 2  66
9   9 2  83
10 10 2 102
# deg 2 rad

deg <-  0:360
PI  <-  atan(1)*4 #the exact value of pi
rad <-  deg*PI/180



rad.df <- data.frame(deg, PI, rad)


#head()와 tail()함수는 각각 자료의 앞과 뒤를 반환하는 함수이며,
#rbind() 함수는 차원이 동일하며 같은 열이름을 지닌 df를 합쳐준다.
rbind(head(rad.df,n=3),tail(rad.df,n=3))
    deg       PI        rad
1     0 3.141593 0.00000000
2     1 3.141593 0.01745329
3     2 3.141593 0.03490659
359 358 3.141593 6.24827872
360 359 3.141593 6.26573201
361 360 3.141593 6.28318531


3.3.4 데이터 프레임에서 데이터 선택 및 추출

이 부분에서는 데이터 프레임에서 자료를 선택하고 이를 추출하는 방법에 대해 다룬다.

아래의 예시에서 반환되는 데이터는 모두 변수에 저장하여 사용이 가능하다.

# name 열(변수) 데이터 추출
# 데이터프레임과 컬럼사이에 $기호가 사용됨

df$name # df[,1], df[, "name"]와 동일
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# df$name 대신 아래처럼 사용 가능

df[, "name"]
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# 첫번째 열(name) 추출

df[, 1]
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# 1열과 3열 추출 
# 여러 항목을 넣을 때는 배열 형식인 c(1,6,8:11)으로 할 것.

df[, c(1, 3)]
    name sex
1 유재석  남
2 홍진영  여
3 송가인  여
4 강호동  남
5 이영자  여
6 김종민  남
7 김연아  여
# name 열(변수)의 3번째 데이터 추출

df$name[3]
[1] "송가인"
# 2~3번째 행 추출

df[2:3, ]
    name age sex score
2 홍진영  28  여    80
3 송가인  31  여    85
# 연령 변수의 데이터를 추출하여 평균을 구함
# na.rm = TRUE는 missing value를 제외하고 계산함

mean(df$age, na.rm = TRUE)
[1] 26.57143

아래와 같이 특정 영역을 제외하고 추출할 수 있다.

# 3번째 열 제외

df[, -3]
    name age score
1 유재석  24    90
2 홍진영  28    80
3 송가인  31    85
4 강호동  25    75
5 이영자  27    95
6 김종민  22    80
7 김연아  29    70

행 또한 위와같이 -기호를 사용하여 적용 가능하다.



혹은 다음과 같이 조건을 적용하여 추출이 가능하다.

# score가 90이상인 데이터 추출
df[df$score >= 90, ]
    name age sex score
1 유재석  24  남    90
5 이영자  27  여    95
# score가 90이상인 데이터의 name과 age만 추출
# 1:2 대신 c("name", "age")를 사용해도 됨
df[df$score >= 90, 1:2]
    name age
1 유재석  24
5 이영자  27
# 조건식과 출력 컬럼명을 변수에 입력하고 이를 활용
score90 <- df$score >= 90
cols <- c("name", "age")
df[score90, cols]
    name age
1 유재석  24
5 이영자  27



subset()함수 사용시

# score가 90이상인 데이터 추출  문법: subset(df, 조건)
subset(df, score >= 90)
    name age sex score
1 유재석  24  남    90
5 이영자  27  여    95
# score가 90이상인 데이터의 name과 age만 추출
subset(df, score >= 90, select = c(name, age))
    name age
1 유재석  24
5 이영자  27
# score가 90이상인 데이터에서 age와 sex만 제외하고 추출
subset(df, score >= 90, select = -c(age,sex))
    name score
1 유재석    90
5 이영자    95


3.3.5 데이터 프레임의 구조 수정


열 추가/삭제

데이터 프레임의 가장 오른쪽에 열을 추가하는 방법이다.

#배열 생성
radian <- rad.df$rad[c(1,91,181,271,361)]
PI <- rad.df$PI[c(1,91,181,271,361)]
deg <- radian*180/PI


# 데이터 프래임 생성
rad2deg <- data.frame(radian,deg)

# 추가할 열 생성
`rad/pi` <- radian/PI #0, 1/2, 1, 3/2, 2


# rad2deg df의 rad/pi 열을 rad/pi로 정의하여 추가
rad2deg$`rad/pi` <- `rad/pi`

rad2deg
    radian deg rad/pi
1 0.000000   0    0.0
2 1.570796  90    0.5
3 3.141593 180    1.0
4 4.712389 270    1.5
5 6.283185 360    2.0

아래는 원하는 열을 삭제하는 방법이다.

#삭제
## 불필요 열 생성

rad2deg$tmp <- "tmp"

rad2deg
    radian deg rad/pi tmp
1 0.000000   0    0.0 tmp
2 1.570796  90    0.5 tmp
3 3.141593 180    1.0 tmp
4 4.712389 270    1.5 tmp
5 6.283185 360    2.0 tmp
## 삭제

rad2deg <- rad2deg[,-c(3,4)] # 3번 열과 4번 열 삭제

rad2deg
    radian deg
1 0.000000   0
2 1.570796  90
3 3.141593 180
4 4.712389 270
5 6.283185 360


행 추가/삭제

데이터 프레임의 하단에 행을 추가하는 방법이다.

new_data <- list("김남준", 24, "남", 92)
new_data
[[1]]
[1] "김남준"

[[2]]
[1] 24

[[3]]
[1] "남"

[[4]]
[1] 92
df <- rbind(df, new_data)
df
    name age sex score
1 유재석  24  남    90
2 홍진영  28  여    80
3 송가인  31  여    85
4 강호동  25  남    75
5 이영자  27  여    95
6 김종민  22  남    80
7 김연아  29  여    70
8 김남준  24  남    92
new_data <- data.frame(
  name = "이지은",
  age = 26,
  sex = "여",
  score = 93)

df <- rbind(df, new_data)
df
    name age sex score
1 유재석  24  남    90
2 홍진영  28  여    80
3 송가인  31  여    85
4 강호동  25  남    75
5 이영자  27  여    95
6 김종민  22  남    80
7 김연아  29  여    70
8 김남준  24  남    92
9 이지은  26  여    93

다음은 원하는 행을 삭제하는 방법이다.

# 행 삭제
removed <- df[-c(2:8),] # 2~8행 삭제

removed
    name age sex score
1 유재석  24  남    90
9 이지은  26  여    93


3.3.6 데이터 프레임 자료 수정

df
    name age sex score
1 유재석  24  남    90
2 홍진영  28  여    80
3 송가인  31  여    85
4 강호동  25  남    75
5 이영자  27  여    95
6 김종민  22  남    80
7 김연아  29  여    70
8 김남준  24  남    92
9 이지은  26  여    93

위와 같은 데이터 프레임에서 홍진영의 점수를 100점으로 바꾸려면..

df[2,4] <- 100. # df[행#,열#]

# 목록에 조교 추가!
df[9,1] <- "서용훈"
df[9,3] <- "남"
df
    name age sex score
1 유재석  24  남    90
2 홍진영  28  여   100
3 송가인  31  여    85
4 강호동  25  남    75
5 이영자  27  여    95
6 김종민  22  남    80
7 김연아  29  여    70
8 김남준  24  남    92
9 서용훈  26  남    93

위와 같이 행번호와 열번호를 지정하여 데이터를 수정할 수 있다.

3.4 자료 입출력

3.4.1 경로 개념 - 절대경로와 상대경로

엑셀과 같은 외부 데이터를 불러오기에 앞서, 파일 경로에 대한 이해가 필요하기 때문에 마련한 부분이다. 익혀두면 R 뿐만이 아니라 다른 프로그래밍을 할 때에도 도움이 되는 부분이라 생각된다.


절대경로

’절대경로(Absolute Path)’는 자신이 원하는 경로를 Root 디렉터리부터 모두 적은 것을 의미한다. 현재 문서를 작성하는 작업공간(working directory)을 예로 들자면, Windows 운영체제에서는 아래와 같이 적은 것이 절대경로이다.

‘작업공간’ 혹은 ’작업 폴더’는 데이터를 불러오거나 외부로 저장하는 작업을 수행하는 기본 폴더이다. 쉽게 말해서 작업이 이루어지는 공간으로, 파일을 읽거나 저장할 때, 경로를 지정하지 않으면 해당 폴더로 저장된다.

현재 문서의 작업공간은 다음과 같다.

# 현재 작업공간을 절대경로로 반환
getwd()
[1] "E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS"

getwd() 함수의 반환 값으로 알 수 있는 현재 작업경로의 절대경로는 다음과 같다.

E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS


상대경로

’상대 경로(Relative Path)’는 특정 경로를 기준으로 다른 경로는 표시하는 개념이다. 상대경로를 표시할 때는 ‘.’‘..’을 함께 많이 사용하는데 ‘.’은 현재 경로(Current Directory)를 의미하고 ‘..’은 상위 경로(Parent Directory)를 의미한다.

예를 들어 현재 작업 공간을 상대경로로 다시 나타낸다면 다음과 같이 나타낼 수 있다.

.

간단하지요?

진짜인지 확인하기 위해 작업공간을 설정할 수 있는 setwd() 함수를 이용하여 확인해보자.

# 작업공간 설정
setwd(".") # 경로는 문자열로 받기 때문에 "your_dir" 씌울 것

getwd()
[1] "E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS"

절대경로에서 확인한 경로와 동일함을 알 수 있다.

참고로 ‘..’은 상위 경로를 탐색할 때 사용되고, 하위 경로를 탐색할 때에는 절대경로와 동일하게 원하는 파일이나 폴더를 명시하면 된다. ‘.’은 현재 경로를 명시적으로 나타낼 때 사용된다.

# 예시
## 여기서 사용된 dir() 함수는 입력된 경로의 파일/폴더 목록을 보여준다.

# 절대경로 - 현재 작업공간
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS

dir(getwd())
[1] "data"                "Ex8.html"            "Ex8.Rmd"            
[4] "fig"                 "서울시데이터셋.html"
# 상대경로 - 현재 작업공간
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS

dir(".")
[1] "data"                "Ex8.html"            "Ex8.Rmd"            
[4] "fig"                 "서울시데이터셋.html"
# 상대경로 - 현재 작업공간의 상위 폴더
# E:/workspace/active/ComputerCartography(TA)/ex8_rev

dir("./..") # `./` <- 현재 경로임을 명시적으로 선언
[1] "lab7"   "webGIS"
# 상대경로 - 현재 작업공간에 위치한 'data' 폴더(하위)
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS/data

dir("./data/")
[1] "Datasets" "html"     "raster"   "Rawdata"  "shp"     

상대경로의 장점은 프로젝트 파일을 다른 사람과 공유할 때, 보통 R 문서(확장자가 .R, .Rmd)이 포함된 작업공간 폴더를 통째로 공유한다면 공유를 받은 사람이 작업시 경로를 하나하나 해당 작업공간에 맞게 변경하지 않아도 되는 장점이 있다.

절대경로는 작업공간이 아닌 D 드라이브와 같은 자료 저장소에서 자료를 불러올 때 유용하다. 만약 저장소 파일을 상대경로로 지정한다면, 사용자의 PC 내에서 R 문서를 옮긴다면 오히려 파일 경로가 깨질 것이다.

다음의 사진을 보면 이해가 빠를 것이다.


상대경로와 절대경로

3.4.2 구분자 형식 외부 데이터 R로 불러오기

이제부터는 여러 파일 형식의 파일을 불러오는 방법을 알아볼 것이다.

이 섹션에서 다루는 함수는 readr 패키지이며, 이는 tidyverse에 포함되어 있으므로, 보통 tidyverse만 불러오면 될 것이다. 기존 R base에도 유사한 함수가 존재하나 성능 및 tibble 지원 때문에 readr 패키지의 함수를 사용하는 것을 권장한다.

readr의 함수 대부분은 파일을 데이터 프레임으로 바꾸는데 특화되어있다.

구분자(delimiter)로 이루어진 파일을 읽는 함수는 다음과 같다.

  • read_csv() : 콤마(,) 구분자 파일(csv)
  • read_csv2(): 세미콜론(;) 구분자 파일
  • read_tsv : 탭( ) 구분자 파일
  • read_delim(): 모든 구분자 파일

위 함수의 사용 방법이 유사한 관계로 이 중 모든 형식의 구분자를 받을 수 있는 read_delim() 함수를 사용해보도록 하겠다.

쉼표 구분자 파일(CSV)

다음과 같이 쉼표로 구분되어 있는 형식의 데이터 파일을 Comma-Separated Values(CSV) 파일이라고 하며 메모장을 이용하여 열어본다면 다음과 형식으로 나타날 것이다.

지점,시작일,종료일,지점명,지점주소,관리관서,위도,경도,노장해발고도(m),기압계(관측장비지상높이(m)),기온계(관측장비지상높이(m)),풍속계(관측장비지상높이(m)),강우계(관측장비지상높이(m)) 400,2019-05-29,,강남,서울특별시 강남구일원동 580탄천 물재생센터 ,,37.4982,127.0816,28.7…..

위와 같은 형식의 파일을 tibble(데이터프레임과 유사) 형식으로 가져오려면…

# read_csv()와 동일
seoul_obs_loc <- read_delim("./data/Rawdata/IO/META_관측지점정보_20200627233901.csv",#상대경로
                          locale=locale('ko',encoding='euc-kr')) # 파일인코딩 설정


seoul_obs_loc
# A tibble: 65 x 13
    지점 시작일     종료일     지점명 지점주소            관리관서     위도  경도
   <dbl> <date>     <date>     <chr>  <chr>               <chr>       <dbl> <dbl>
 1   400 2019-05-29 NA         강남   "서울특별시 강남구~ <NA>         37.5  127.
 2   400 2010-08-16 2019-05-29 강남   "서울특별시 강남구~ <NA>         37.5  127.
 3   400 1994-12-04 2010-08-15 강남   "서울특별시 강남구~ 서울기상관~  37.5  127.
 4   401 2016-09-12 NA         서초   "서울특별시 서초구~ <NA>         37.5  127.
 5   401 2010-08-16 2016-09-12 서초   "서울특별시 서초구~ <NA>         37.5  127.
 6   401 1994-12-04 2010-08-15 서초   "서울특별시 서초구~ 서울기상관~  37.5  127.
 7   402 2010-08-16 NA         강동   "서울특별시 강동구~ <NA>         37.6  127.
 8   402 1994-12-04 2010-08-15 강동   "서울특별시 강동구~ 서울기상관~  37.6  127.
 9   403 2010-08-16 NA         송파   "서울특별시 송파구~ <NA>         37.5  127.
10   403 1994-12-05 2010-08-15 송파   "서울특별시 송파구~ 서울기상관~  37.5  127.
# ... with 55 more rows, and 5 more variables: 노장해발고도(m) <dbl>,
#   기압계(관측장비지상높이(m)) <dbl>, 기온계(관측장비지상높이(m)) <dbl>,
#   풍속계(관측장비지상높이(m)) <dbl>, 강우계(관측장비지상높이(m)) <dbl>

위와 같이 tibble형식의 데이터 프레임을 불러올 수 있다.

탭 구분자 파일(TSV)

CSV 파일과 유사하지만 구분자가 tab( )인 파일은 다음과 같이 구성되어있다.

기간 자치구 세대 인구 인구 인구 인구 인구 인구 인구 인구 인구 세대당인구 65세이상고령자 기간 자치구 세대 합계 합계 합계 한국인 한국인 한국인 등록외국인 등록외국인 등록외국인 세대당인구 65세이상고령자 기간 자치구 세대 계 남자 여자 계 남자 여자 계 남자 여자 세대당인구 65세이상고령자 2020.1/4 합계 4,354,006 10,013,781 4,874,995 5,138,786 9,733,655 4,742,217 4,991,438 280,126 132,778 147,348 2.24 1,518,239

이를 데이터 프레임 형식으로 불러오려면…

# read_tsv()와 동일
# 이번 파일은 csv 예시와 다르게 인코딩이 패키지 기본 값인 UTF-8이므로
# 추가적으로 인코딩 선언은 불필요함
seoulGU21 <- read_delim("./data/Rawdata/population/20201stQGu.txt")

seoulGU21
# A tibble: 28 x 14
   기간     자치구   세대  인구...4 인구...5 인구...6 인구...7 인구...8 인구...9
   <chr>    <chr>    <chr> <chr>    <chr>    <chr>    <chr>    <chr>    <chr>   
 1 기간     자치구   세대  합계     합계     합계     한국인   한국인   한국인  
 2 기간     자치구   세대  계       남자     여자     계       남자     여자    
 3 2020.1/4 합계     4,35~ 10,013,~ 4,874,9~ 5,138,7~ 9,733,6~ 4,742,2~ 4,991,4~
 4 2020.1/4 종로구   74,1~ 161,984  78,271   83,713   151,217  73,704   77,513  
 5 2020.1/4 중구     63,0~ 136,469  66,769   69,700   126,175  61,839   64,336  
 6 2020.1/4 용산구   110,~ 246,165  119,961  126,204  229,579  110,667  118,912 
 7 2020.1/4 성동구   135,~ 307,193  149,891  157,302  299,042  146,300  152,742 
 8 2020.1/4 광진구   165,~ 365,990  176,226  189,764  350,417  169,568  180,849 
 9 2020.1/4 동대문구 165,~ 362,793  178,202  184,591  346,156  171,896  174,260 
10 2020.1/4 중랑구   182,~ 400,678  198,122  202,556  395,619  196,076  199,543 
# ... with 18 more rows, and 5 more variables: 인구...10 <chr>,
#   인구...11 <chr>, 인구...12 <chr>, 세대당인구 <chr>, 65세이상고령자 <chr>

3.4.3 외부로부터 공간자료 불러오기

앞서 다뤘던 구분자 형식의 자료를 R 외부로부터 불러왔던 것과 같이, 이전 실습에서 다루었던 셰이프(.shp) 형식의 공간자료를 불러오는 법과 래스터 형식의 자료(.img)파일을 불러오는 방법을 살펴볼 것이다.

Shapefiles(.shp)

셰이프 파일을 불러오는 함수는 여러 개가 존재하나, 이번 실습에서는 rgdal 패키지를 사용하여 진행하고자 한다.

다음의 코드를 사용하여 rgdal 패키지를 설치하도록 한다.

if (require("rgdal")) {
    # 참: 패키지 존재
    print("패키지있어유~") 
} else {
    # 거짓: 패키지 설치
    print("패키지깔게유~") 
    install.packages("rgdal")
}
[1] "패키지있어유~"
library(rgdal) # 패키지 로드

아래는 rgdal패키지의 함수인 readOGR() 함수를 사용하여 shp 파일을 불러오는 코드이다.

# 남한 시군구 shp를 불러오기

sigungu <- readOGR(dsn = "./data/shp/구",     # dsn: shp파일 위치 경로
                   layer = "kr_si_gun-gu",    # layer: 확장자를 제외한 파일명
                   encoding = "UTF-8",        # 속성 테이블 인코딩
                   stringsAsFactors = FALSE,  # 문자열을 factor로 받을지 선택
                   verbose = FALSE)           # 로드 시 여러 메시지를 띄울지 여부

shp 파일을 불러왔으면 다음과 같은 명령으로 속성테이블(attribute table)을 데이터프레임 형식으로 조회할 수 있다.

# attr table
sigungu@data # shp지정변수명@data
   SIG_CD      SIG_ENG_NM SIG_KOR_NM
0   11110       Jongno-gu     종로구
1   11140         Jung-gu       중구
2   11170      Yongsan-gu     용산구
3   11200    Seongdong-gu     성동구
4   11215     Gwangjin-gu     광진구
5   11230   Dongdaemun-gu   동대문구
6   11260     Jungnang-gu     중랑구
7   11290     Seongbuk-gu     성북구
8   11305      Gangbuk-gu     강북구
9   11320       Dobong-gu     도봉구
10  11350        Nowon-gu     노원구
11  11380    Eunpyeong-gu     은평구
12  11410    Seodaemun-gu   서대문구
13  11440         Mapo-gu     마포구
14  11470    Yangcheon-gu     양천구
15  11500      Gangseo-gu     강서구
16  11530         Guro-gu     구로구
17  11545    Geumcheon-gu     금천구
18  11560 Yeongdeungpo-gu   영등포구
19  11590      Dongjak-gu     동작구
20  11620       Gwanak-gu     관악구
21  11650       Seocho-gu     서초구
22  11680      Gangnam-gu     강남구
23  11710       Songpa-gu     송파구
24  11740     Gangdong-gu     강동구
 [ reached 'max' / getOption("max.print") -- omitted 225 rows ]
# 데이터프레임 형식과 동일하여 아래와 같이 속성테이블만 df로 추출 가능
# sigungu.as.df <- sigungu@data

불러온 이후에는 plot() 함수를 사용하여 간단하게 도시할 수 있다.

# 시각화


# 패키지명::함수()
# 위와 같은 형식으로 패키지를 명시하면 패키지를 불러오지 않더라도
# 패키지 내장 함수를 불러올 수 있다. 또한 동명의 패키지가 있어
# 시스템이 어느 패키지를 지정 못함으로 인해 발생하는 오류를 해결할 때도
# 이를 사용하면 해결이 가능함.

sp::plot(sigungu)

Raster files(.img)

R에서는 래스터 형식의 파일도 처리할 수 있다. raster 패키지는 해당 기능을 지원한다.

if (require("raster")) {
    # 참: 패키지 존재
    print("패키지있어유~") 
} else {
    # 거짓: 패키지 설치
    print("패키지깔게유~") 
    install.packages("raster")
}
[1] "패키지있어유~"
library(raster)

다음은 raster 패키지의 raster() 함수를 사용하여 서울특별시 수치표고모델(DEM)을 불러오는 과정이다.

seoulDEM30 <- raster("./data/raster/seoul_dem.img")   # 주의! 경로에 한글이나 띄어쓰기가 있으면 오류남!

# raster::plot() 사용

{                                                     # 한번에 실행 가능한 중괄호
  plot(seoulDEM30,                                    # plot 대상(필수)
       legend.args = list(text = 'Elevation (m)',     # 범례 제목 넣기
       side = 4, font = 2, line = 2.5, cex = 0.8))    # 범례 꾸미기 설정
  title("서울시 수치표고모형", sub = crs(seoulDEM30), # 여러 타이틀 설정
        xlab = "x(meter)", ylab = "y(meter)",         # 여기서 crs()는 좌표계 반환
        cex.main= 2, font.main= 4, col.main= "blue",  # 타이틀 꾸미기 설정
        cex.sub= 0.75, font.sub= 3, col.sub= "black")
 
}                                                     # 괄호는 항상 닫아주기

3.5 R GIS

3.5.1 공간자료 다루기

좌표계 설정

define projection

좌표투영이 되어있지 않은 파일이라 해당 자료를 가지고 도시를 하면 다음과 같이 올바르게 도시되지 않는다.

seoulemd <- readOGR(dsn = "./data/shp/행정동", 
                    layer = "Z_SOP_BND_ADM_DONG_PG", 
                    encoding = "UTF-8",
                    stringsAsFactors = FALSE,
                    verbose = FALSE)[c(1:424),] # 424행까지 - 서울시만 추출

library(tmap)
library(tmaptools)
library(OpenStreetMap) # https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245060_d3c52aa6bfa54d3ca74e617f18309292

osm_seoul <- read_osm(seoulDEM30)
tm_shape(osm_seoul) + tm_rgb() + tm_shape(seoulemd) + tm_polygons()

따라서 해당 자료 제작시 어떠한 좌표 체계를 사용하였는지 파악하는게 중요하다. 대부분 자료를 제공하는 사이트 상에서 알 수 있다.

구득 웹 사이트(국가공간정보포털 오픈마켓) 상에서 메타데이터를 확인하여, 지리원 표준 좌표계 중 하나인 ‘EPSG:5181’(중부원점, GRS80)로 좌표계를 다음과 같이 정의해주었다.

seoulemd@proj4string <- CRS("+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +units=m +no_defs")

tm_shape(osm_seoul) + tm_rgb() + tm_shape(seoulemd) + tm_polygons(alpha = 0.5)

정상적으로 중첩이 되는 것을 볼 수 있다.

이러한 과정이 불편하다면, 불러올 때 readOGR() 함수의 p4s 파라미터로 한번에 처리가 가능하다.

seoulemd <- readOGR(dsn = "./data/shp/행정동", 
                    layer = "Z_SOP_BND_ADM_DONG_PG", 
                    encoding = "UTF-8",
                    stringsAsFactors = FALSE,
                    verbose = FALSE,
                    p4s = "+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +units=m +no_defs")[c(1:424),]

tm_shape(osm_seoul) + tm_rgb() + tm_shape(seoulemd) + tm_polygons(alpha = 0.5)

좌표계 변환

project

seoulgwanak <- subset(sigungu, SIG_KOR_NM == "관악구")

{
em1 <- crop(seoulDEM30, extent(seoulgwanak), snap="out")
fr1 <- rasterize(seoulgwanak, em1)
DEMgwanak <- mask(x = em1, mask = fr1)
}
Error in .local(x, y, ...): extents do not overlap
crs(seoulgwanak)  # EPSG:5179,  UTM-K,   GRS80 
CRS arguments:
 +proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000
+ellps=GRS80 +units=m +no_defs 
crs(seoulDEM30)   # EPSG:32652, UTM 52N, WGS84
CRS arguments:
 +proj=utm +zone=52 +datum=WGS84 +units=m +no_defs 
UTM52N <- CRS("+proj=utm +zone=52 +ellps=WGS84 +datum=WGS84 +units=m +no_defs") #EPSG:32652, UTM 52N, WGS84

gwanakUTM <- spTransform(seoulgwanak, UTM52N)

crs(gwanakUTM) #EPSG:32652, UTM 52N, WGS84
CRS arguments:
 +proj=utm +zone=52 +datum=WGS84 +units=m +no_defs 
{
em1 <- crop(seoulDEM30, extent(gwanakUTM), snap="out")
fr1 <- rasterize(gwanakUTM, em1)
DEMgwanak <- mask(x = em1, mask = fr1)
}

plot(DEMgwanak)

위경도 좌표로 공간자료 생성

해당 문서에서 정제한 올리브영 자료는 2020년 7월 19일 기준이다.

해당 자료는 올리브영 매장안내에서 구득하였다.

자료 정제 과정?

oliveyoungXY <- read_csv("./data/Datasets/Oliveyoung/Oliveyoung.csv")

테이블 Join

해당 자료는 서울시 주민등록인구 (구별) 통계에서 구득하였다.

seoulgupop2020 <- read_csv("./data/Datasets/Population/20201stQGu.csv")

seoulGU <- subset(sigungu, SIG_CD <= 11740)

plot(seoulGU)

지도 대수(Map Algebra)

NDVI

3.5.2 시각화(tmap)

if (require("tmap")) {
    # 참: 패키지 존재
    print("패키지있어유~") 
} else {
    # 거짓: 패키지 설치
    print("패키지깔게유~") 
    install.packages("tmap")
}
[1] "패키지있어유~"
library(tmap)

기초 문법

load(url("http://github.com/mgimond/Spatial/raw/master/Data/Sample1.RData"))

회색의 기본적인 지도를 만들려면 다음을 입력한다.

tmap_mode("plot") # 일반 그림 지도

tm_shape(s.sf) + tm_polygons()

tm_shape() 함수는 공간자료를 패키지로 불러오는 역할을 하며 공간자료는 vector 형식이나 raster 형식이 될 수 있다. tm_polygons 함수는 tmap 패키지에서 어떻게 공간자료가 도시되는지 표현하는 여러 명령 중 하나이다.

tm_polygons 함수에 col= 파라미터를 넣어서 단순히 단색으로 채워 넣을 수도, 속성 값에 따라 색상의 변화를 줄 수도 있다.

tm_shape(s.sf) + tm_polygons(col="Income", border.col = "white") # border.col <- 경계선 색상

여기서 우리의 목표는 웹 상에 올려서 웹 GIS를 만드는 것이기 때문에 다음과 같은 코드로 html 형식의 지도를 만들 것이다.

tmap_mode("view") # 상호작용 지도

tm_shape(s.sf) + tm_polygons(col="Income", border.col = "red")

tmap_mode("view")는 정적인(static) 지도가 아닌 상호작용이 가능한 웹 문서에서 많이 쓰이는 html 형식의 지도를 제공한다.

Point 형식

AQstations <- readOGR(dsn = "./data/shp/point",
                      layer = "AQstations",
                      encoding = "UTF-8",
                      use_iconv=TRUE,           #esri shapefile 설정
                      stringsAsFactors = FALSE,
                      verbose = FALSE)
names(AQstations@data) <- c("측정일시", "측정소명", "이산화질소농도(ppm)", "오존농도(ppm)", "이산화탄소농도(ppm)", "아황산가스(ppm)", "미세먼지(㎍/㎥)", "초미세먼지(㎍/㎥)","주소",  "지점명", "일일교통량(대)", "lon", "lat")



traffic <- readOGR(dsn = "./data/shp/point",
                   layer = "traffic",
                   encoding = "UTF-8",
                   use_iconv=TRUE,           #esri shapefile 설정
                   stringsAsFactors = FALSE,
                   verbose = FALSE)

names(traffic@data) <- c("지점번호","지점명","경도","위도")
tmap_mode("view")

lung <- tmap_icons("./fig/lung.png")
car  <- tmap_icons("./fig/car.png")

tm_shape(AQstations) +
  tm_symbols("측정소명", id="측정소명",size = 0.5, legend.col.show = FALSE)+
tm_shape(traffic) +
  tm_symbols("지점명", id="지점명",size = 0.5,shape = car,legend.col.show = FALSE)


범례

대기질 관측소

교통정보 수집지점

Polyline 형식

Polygon 형식

Raster 형식

tmap_mode("view")


tm_basemap(c("Stamen.Terrain","OpenStreetMap.HOT")) +     # 배경지도(basemap)
tm_shape(seoulDEM30)  +                                   # tm_shape
tm_raster(n=10^5,                                         # 간격 수
          palette = "-Spectral",                          # 색 그라데이션 tmaptools::palette_explorer() 참고
          style = "cont",                                 # ArcGIS Symbology의 Classification. 간격 스타일 설정
          title = "Seoul DEM 30M")                        # 범례 제목
                                                          # 자세한 내용은 패키지 로드 후 Console에 ?tm_raster



#tmaptools::palette_explorer()

4 데이터셋 위치

모든 데이터셋은 ./data/Datasets/ 디렉터리 안에 있습니다.

5 정제 데이터셋

데이터셋 랭글링 과정을 담았습니다.

5.1 행정경계 데이터 불러오기

먼저, 분석 스케일의 뼈대가 되는 행정경계 데이터를 불러왔습니다.

5.1.1 사용한 패키지

library(tidyverse)
library(sf)
library(rgdal)
library(raster)
library(tmap)
#library(geojsonio)

5.1.2

전국 시군구 파일에서 시군구 코드를 기준으로 서울 지역만 추출하는 과정입니다.

seoulgu <- readOGR(dsn = "./data/shp/구",
                       layer = "kr_si_gun-gu",
                       encoding = "UTF-8",
                       stringsAsFactors = FALSE,
                       verbose = FALSE) %>% 
           subset(SIG_CD <= 11740)

#seouldong <- readOGR(dsn = "./data/shp/행정동",
#                       layer = "HangJeongDong_ver20200401.ㅓ",
#                       encoding = "UTF-8",
#                       stringsAsFactors = FALSE,
#                       verbose = FALSE)# %>%  subset(SIG_CD < 20000)

#sqlseoul <- "SELECT * FROM As features WHERE 'adm_cd' < '20000'"

#seouldong <- geojson_read("./data/shp/행정동/HangJeongDong_ver20200401.geojson", parse = FALSE, what = "sp", stringsAsFactors = FALSE)[c(1:425),]

5.1.3 행정동

좌표투영이 되어있지 않은 파일이라 구득 웹 사이트(국가공간정보포털 오픈마켓) 상에서 메타데이터를 확인하여, 지리원 표준 좌표계 중 하나인 ‘EPSG:5181’(중부원점, GRS80)로 좌표계를 정의해주고, 불러옴과 동시에 서울 행정동만 추출하였습니다.

seoulemd <- readOGR(dsn = "./data/shp/행정동", 
                    layer = "Z_SOP_BND_ADM_DONG_PG", 
                    encoding = "UTF-8",
                    stringsAsFactors = FALSE,
                    verbose = FALSE,
                    p4s = "+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +units=m +no_defs")[c(1:424),] %>% spTransform(crs(seoulgu))
tmap_mode("view")
tm_shape(seoulemd) + tm_polygons() + tm_shape(seoulgu) + tm_polygons(alpha = 0.7)

5.2 서울시 인구

서울시 인구 자료를 정제하였으며, 2020년 1/4분기 자료입니다.

5.2.1 사용한 패키지

library(tidyverse)  # 정제 필수 패키지
library(DT)         # 동적 테이블 시각화

# 공간자료화 및 시각화
library(sf)
library(rgdal) # .rmd 상에서 필요
library(tmap)
library(raster)
library(leafem) # leaflet

5.2.2 자료의 출처

해당 자료는 서울시 주민등록인구 (구별) 통계서울시 주민등록인구 (동별) 통계에서 구득하였습니다.

5.2.3 정제 과정 - 구

먼저 앞서 언급한 웹 페이지에서 구득한 구분자(Delimiter)로 구성된 파일을 불러왔습니다.

library(tidyverse)

pop.gu <- read_tsv("./data/Rawdata/population/20201stQGu.txt")
# 작업이 행해지는 객체(Object) 대신
# 작업의 흐름을 강조하기 위해 '%>%'를 사용함
# '%>%'는 '파이프' 연산자라고 칭함

# https://style.tidyverse.org/pipes.html <- 참고

# 참고로 위와 같은 코드는 다음과 같이 나타낼 수 있다.

  # subset(
  #        readOGR(dsn = "./data/shp/구",
  #                layer = "kr_si_gun-gu",
  #                encoding = "UTF-8",
  #                stringsAsFactors = FALSE,
  #                verbose = FALSE),
  #                                          SIG_CD <= 11740)

```